package com.wangxiaonan.speculation.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wangxiaonan.speculation.dto.DocCountDto;
import com.wangxiaonan.speculation.handler.ResponseWrapper;
import com.wangxiaonan.speculation.service.QueryService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author: wangxiaonan
 * @Date: 2019/7/4
 **/
@CrossOrigin
@RestController
@RequestMapping("/es")
public class QueryController {

    private static final Logger logger = LoggerFactory.getLogger(QueryController.class);

    private static final String ALL_DATA_KEY = "all";

    @Resource
    private QueryService queryService;

    /**
     * {
     * "size": 0,
     * "from": 0,
     * "minTime": "2019-06-25 00:00:00",
     * "maxTime": "2019-06-29 00:00:00",
     * "format": "yyyy-MM-dd HH:mm:ss",
     * "interval": "day",
     * "matches": {
     * "eventKey": "homepage_mainpage_pageRefresh",
     * "appType": "IOS"
     * },
     * "indices": ["app-front-event-info27"],
     * "types": ["_doc"]
     * }
     */
    @RequestMapping(value = "/search", method = RequestMethod.POST)
    public ResponseWrapper search(@RequestBody DocCountDto docCount) {

        JSONArray array = getCharData(docCount);

        JSONObject data = new JSONObject();

        if (!array.isEmpty()) {
            JSONArray axisX = new JSONArray();
            JSONArray axisY = new JSONArray();
            JSONArray axisYData = new JSONArray();
            for (Object x : array.toArray(new Object[0])) {
                JSONObject i;
                try {
                    i = JSONObject.parseObject(String.valueOf(x));
                } catch (Exception e) {
                    continue;
                }
                axisX.add(i.getString("key_as_string"));
                axisYData.add(i.getString("doc_count"));
            }
            if (!axisX.isEmpty() && !axisYData.isEmpty()) {
                JSONObject item = new JSONObject();
                item.put("data", axisYData);
                item.put("name", "新注册用户");
                axisY.add(item);
                data.put("axis_x", axisX);
                data.put("axis_y", axisY);
            }
        }

        return new ResponseWrapper().success().setData(data);
    }

    /**
     * {
     * "size": 0,
     * "from": 0,
     * "pageSize": 10,
     * "pageNum": 1, 从1开始
     * "minTime": "2019-06-25 00:00:00",
     * "maxTime": "2019-06-29 00:00:00",
     * "format": "yyyy-MM-dd HH:mm:ss",
     * "interval": "day",
     * "matches": {
     * "eventKey": "homepage_mainpage_pageRefresh",
     * "appType": "IOS"
     * },
     * "indices": ["app-front-event-info27"],
     * "types": ["_doc"]
     * }
     */
    @RequestMapping(value = "/search/detail", method = RequestMethod.POST)
    public ResponseWrapper detail(@RequestBody DocCountDto docCount) {
        if (docCount.getPageSize() == 0) {
            docCount.setPageSize(10);
        }

        JSONArray array = getCharData(docCount);

        int pageNum0 = docCount.getPageNum() < 1 ? 0 : docCount.getPageNum() - 1;
        int fromIndex = pageNum0 * docCount.getPageSize();
        int toIndex = fromIndex + docCount.getPageSize();

        JSONObject result = new JSONObject();
        List<Object> subList;
        if (array.isEmpty() || fromIndex >= array.size()) {
            subList = new ArrayList<>();
        } else if (toIndex <= array.size()) {
            subList = array.subList(fromIndex, toIndex);
        } else {
            subList = array.subList(fromIndex, array.size());
        }

        result.put("total", array.size());
        result.put("items", subList);
        result.put("pageNum", pageNum0 + 1);
        result.put("pageSize", docCount.getPageSize());

        return new ResponseWrapper().success().setData(result);
    }

    private JSONArray getCharData(DocCountDto docCount) {
        Set<String> indices = docCount.getIndices();
        if (CollectionUtils.isEmpty(indices)) {
            indices = new HashSet<>();
            indices.add("app-front-event-info27");
        }

        Set<String> types = docCount.getTypes();
        if (CollectionUtils.isEmpty(types)) {
            types = new HashSet<>();
            types.add("_doc");
        }

        JSONObject queryStr = new JSONObject();
        queryStr.put("size", docCount.getSize());
        queryStr.put("from", docCount.getFrom());

        // aggs
        JSONObject aggs = new JSONObject();
        JSONObject groupByState = new JSONObject();
        JSONObject dateHistogram = new JSONObject();
        JSONObject extendedBounds = new JSONObject();

        extendedBounds.put("min", docCount.getMinTime());
        extendedBounds.put("max", docCount.getMaxTime());

        dateHistogram.put("extended_bounds", extendedBounds);
        dateHistogram.put("field", "@timestamp");
        dateHistogram.put("interval", docCount.getInterval());
        dateHistogram.put("format", docCount.getFormat());

        groupByState.put("date_histogram", dateHistogram);

        aggs.put("group_by_state", groupByState);

        queryStr.put("aggs", aggs);

        // query
        JSONObject bool = new JSONObject();
        JSONObject filter = new JSONObject();
        JSONObject range = new JSONObject();
        JSONObject timestamp = new JSONObject();
        JSONArray must = new JSONArray();

        timestamp.put("gte", docCount.getMinTime());
        timestamp.put("lte", docCount.getMaxTime());
        timestamp.put("format", docCount.getFormat());

        range.put("@timestamp", timestamp);

        filter.put("range", range);

        bool.put("filter", filter);

        Map<String, String> matches = docCount.getMatches();
        if (matches == null) {
            matches = new HashMap<>();
        }
        for (Map.Entry<String, String> match : matches.entrySet()) {
            JSONObject matchObject = new JSONObject();
            JSONObject matchValue = new JSONObject();
            if (ALL_DATA_KEY.equals(match.getValue())) {
                continue;
            }
            matchValue.put(match.getKey(), match.getValue());
            matchObject.put("match", matchValue);
            must.add(matchObject);
        }

        bool.put("must", must);

        JSONObject query = new JSONObject();
        query.put("bool", bool);

        queryStr.put("query", query);

        return queryService
                .queryChartData(queryStr.toJSONString(), indices, types);
    }

}
